/*
    This file is part of qmessages.
    Copyright (C) 2010  Jason Newton <nevion@gmail.com>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef QMSGIO_QMESSAGE_H
#define QMSGIO_QMESSAGE_H
#include <memory>
#include <QDataStream>
#include <functional>
#include <typeinfo>
#include <string>
#include <unordered_map>

namespace qmsgio{

class QMessage{
    public:
        typedef qint32 tag_t;
        typedef std::function<std::unique_ptr<QMessage>()> message_ctor_t;

        virtual ~QMessage(){};

        static int minMessageSize();
        virtual int fixedSize();
        virtual bool parseFixed(QDataStream &stream);
        virtual int variableSize();
        virtual bool parseVariable(QDataStream &stream);
        virtual bool serializeFixed(QDataStream &stream);
        virtual bool serializeVariable(QDataStream &stream);
        virtual bool serialize(QDataStream &stream);
        virtual bool deserialize(QDataStream &stream);

        static std::unique_ptr<QMessage> parseMessageHeader(QDataStream &stream);
        static std::unordered_map<tag_t, message_ctor_t> tag2Ctor;
        static std::unordered_map<std::string, tag_t> type2Tag;
        static void register_message(const tag_t &tag, const std::type_info &class_t, const message_ctor_t &ctor);
        template<typename T>
        static std::unique_ptr<QMessage> message_implementation();
        template<typename T>
        static void register_message(const int &tag);
        template<typename T>
        static void register_message(int &tag);
};

template<typename T>
std::unique_ptr<QMessage> QMessage::message_implementation(){
    return std::unique_ptr<QMessage>((QMessage *)(new T()));
}

template<typename T>
void QMessage::register_message(const int &tag){
    register_message((tag_t) tag, typeid(T), message_ctor_t(message_implementation<T>));
}

}
#endif
